﻿///////////////////////////////////////////////////////////////////////////////
//
// This file is part of the BassDrop project
//   https://code.google.com/p/bass-drop/
//
//
// Creator:	Gergely Krajcsovszki (krajcsovszkig@hotmail.com)
// Date:	2014-04-20 18:25
//
//
// Copyright © 2013-2014. Gergely Krajcsovszki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BassDrop.Core.Common.Data.IO.Data
{
	/// <summary>
	/// Class for the information that can go into the key and meta tags of an xplf file.
	/// It can be used to help identify / check the validity of a mediatrack or to get the most
	/// important pieces of metadata for it without looking it up in the library or the file.
	/// </summary>
	public class MediaKey : CustomMetadata, IEquatable<MediaKey>
	{
		/// <summary>
		/// The hash of the media file
		/// </summary>
		public Hash Hash
		{
			get;
			set;
		}

		/// <summary>
		/// The name of the media file
		/// </summary>
		public string FileName
		{
			get;
			set;
		}

		/// <summary>
		/// The title of the media track in the file
		/// </summary>
		public string Title
		{
			get;
			set;
		}

		/// <summary>
		/// The artist of the media track in the file
		/// </summary>
		public string Artist
		{
			get;
			set;
		}

		/// <summary>
		/// The album of the media track in the file
		/// </summary>
		public string Album
		{
			get;
			set;
		}

		/// <summary>
		/// Merges another MediaKey into this one if possible, throws an exception otherwise
		/// </summary>
		/// <param name="other"></param>
		public void Merge( MediaKey other )
		{
			if ( !Match( other ) )
			{
				throw new InvalidOperationException( "The two MediaKeys cannot be merged" );
			}

			Hash = Hash ?? other.Hash;
			Title = Title ?? other.Title;
			Artist = Artist ?? other.Artist;
			Album = Album ?? other.Album;
		}

		/// <summary>
		/// Returns whether the two keys match (do they possibly refer to the same media item)
		/// </summary>
		/// <param name="other"></param>
		/// <returns></returns>
		public bool Match( MediaKey other )
		{
			return other != null
				&& !((Hash != null && other.Hash != null && Hash != other.Hash)
						|| (Title != null && other.Title != null && Title != other.Title)
						|| (Artist != null && other.Artist != null && Artist != other.Artist)
						|| (Album != null && other.Album != null && Album != other.Album));
		}

		#region IEquatable<MediaKey> Members

		/// <summary>
		/// Indicates whether the current object is equal to another object of the same type.
		/// </summary>
		/// <param name="other">An object to compare with this object.</param>
		/// <returns>true if the current object is equal to the other parameter; otherwise, false.</returns>
		public bool Equals( MediaKey other )
		{
			if ( (object) other == null )
			{
				return false;
			}

			return other.Hash == Hash && other.Title == Title && other.Artist == Artist && other.Album == Album;
		}

		#endregion

		/// <summary>
		/// Determines whether the specified object is equal to the current object.
		/// </summary>
		/// <param name="obj">An object to compare with this object.</param>
		/// <returns>true if the current object is equal to the other parameter; otherwise, false.</returns>
		public override bool Equals( object obj )
		{
			return Equals( obj as MediaKey );
		}

		/// <summary>
		/// Serves as the default hash function.
		/// </summary>
		/// <returns>A hash code for the current object.</returns>
		public override int GetHashCode()
		{
			unchecked
			{
				int hash = 17;

				if ( Hash != null )
				{
					hash = hash * 23 + Hash.GetHashCode();
				}

				if ( Title != null )
				{
					hash = hash * 23 + Title.GetHashCode();
				}

				if ( Artist != null )
				{
					hash = hash * 23 + Artist.GetHashCode();
				}

				if ( Album != null )
				{
					hash = hash * 23 + Album.GetHashCode();
				}

				return hash;
			}
		}

		/// <summary>
		/// Returns whether v1 equals v2
		/// </summary>
		/// <param name="mk1"></param>
		/// <param name="mk2"></param>
		/// <returns></returns>
		public static bool operator ==( MediaKey mk1, MediaKey mk2 )
		{
			if ( System.Object.ReferenceEquals( mk1, mk2 ) )
			{
				return true;
			}

			if ( ((object) mk1 == null) || ((object) mk2 == null) )
			{
				return false;
			}

			return mk1.Equals( mk2 );
		}

		/// <summary>
		/// Returns whether v1 does not equal v2
		/// </summary>
		/// <param name="mk1"></param>
		/// <param name="mk2"></param>
		/// <returns></returns>
		public static bool operator !=( MediaKey mk1, MediaKey mk2 )
		{
			return !(mk1 == mk2);
		}
	}
}
